﻿namespace JoinBox.MathEx.Algorithm;


using System;
using System.Collections.Generic;
using JoinBox.MathEx.TSP;
using System.Linq;

/// <summary>
/// 集合
/// </summary>
public class Colony<TGeneticInfo> // : SelectModeMethod<Tour>
     where TGeneticInfo : TSP.GeneticInfoBasal, new()
{
    #region 成员
    /// <summary>
    /// 染色体父代
    /// </summary>
    readonly List<Chromosome> _chromosomes;

    /// <summary>
    /// 染色体子代(只是用来交换成员)
    /// </summary>
    readonly List<Chromosome> _chromosomesChild = new();

    /// <summary>
    /// 获取fit值
    /// </summary>
    /// <param name="x"></param>
    /// <returns></returns>
    readonly Func<int, int> _Func;

    readonly TGeneticInfo _Info;
    #endregion

    #region 构造

    public Colony(List<Chromosome> tours, TGeneticInfo info, Func<int, int> func)
    {
        _chromosomes      = tours;
        _chromosomesChild = new();
        _Info             = info;
        _Func             = func;
    }

    #endregion

    #region 方法
    /// <summary>
    /// 获取fit值
    /// </summary>
    /// <param name="x"></param>
    /// <returns></returns>
    int GetFitValue(int x)
    {
        return _Func(x);
    }

    /// <summary>
    /// 打印
    /// </summary>
    public void Print(bool bLoadPercent = false)
    {
        Console.WriteLine("=========================");
        for (int i = 0; i < _chromosomes.Count; i++)
        {
            Console.Write($"第" + i.ToString("d2") + "条基因(Bits): ");
            for (int j = 0; j < _chromosomes[i].Bits.Length; j++)
                Console.Write(" " + _chromosomes[i].Bits[j]);
            int x = Helper.DeCode(_chromosomes[i].Bits);
            Console.Write(" x: " + x);
            Console.Write(" y: " + _chromosomes[i].Fitness);
            if (bLoadPercent)
            {
                Console.Write(" 选择概率: " + _chromosomes[i].FitPercent);
                // Console.Write(" 累积概率: " + _chromosomes[i].Probability);// 原作者注释它是为什么?
            }
            Console.WriteLine();
        }
        Console.WriteLine("=========================");
    }

    /// <summary>
    /// 选择染色体方法:从大到小排序
    /// </summary>
    public void SelectSortBubble()
    {
        _chromosomes.Sort((a, b) => { return b.Fitness.CompareTo(a.Fitness); });
    }

    /// <summary>
    /// 修改累计概率,以及父代子代交换,进入下次循环
    /// </summary>
    /// <param name="action"></param>
    void FitChange(Action action)
    {
        // 累计适应度
        double totalFitValue = 0;
        for (int i = 0; i < _chromosomes.Count; i++)
        {
            // 适应度为负数的取0;
            if (_chromosomes[i].Fitness <= 0)
                totalFitValue += 0;
            else
                totalFitValue += _chromosomes[i].Fitness;
        }
        Console.WriteLine("累计适应度(totalFitValue): " + totalFitValue);

        // 算出每个的 适应度百分比;
        for (int i = 0; i < _chromosomes.Count; i++)// 杀掉适应度为负的基因
        {
            if (_chromosomes[i].Fitness <= 0)
                _chromosomes[i].FitPercent = 0;
            else
                _chromosomes[i].FitPercent =
                    _chromosomes[i].Fitness / totalFitValue; // 计算第i个基因的适应值(第i个基于的适应值/累计适应值)
            Console.WriteLine($"第{i}个体选择概率(fitValuePercent):" + _chromosomes[i].FitPercent);
        }

        // 计算累积概率
        // 第一个的累计概率就是自己的概率
        _chromosomes[0].Probability = _chromosomes[0].FitPercent;
        Console.WriteLine("累积概率[0]个: " + _chromosomes[0].Probability);
        double probability = _chromosomes[0].Probability;
        for (int i = 1; i < _chromosomes.Count; i++)
        {
            if (_chromosomes[i].FitPercent != 0) // 只对出现概率概率不为0的染色体进行操作
            {
                _chromosomes[i].Probability = _chromosomes[i].FitPercent + probability;
                probability                 = _chromosomes[i].Probability;
            }
            Console.WriteLine($"累积概率[{i}个]: " + _chromosomes[i].Probability);
        }

        action.Invoke();

        // 更新种群信息
        // 子代变父代,进入下一次循环
        for (int i = 0; i < _chromosomes.Count; i++)
            _chromosomes[i] = _chromosomesChild[i];
    }

    /// <summary>
    /// 选择染色体方法:轮盘赌,进行基因型的选择,更新下一代
    /// </summary>
    public void SelectRoulette()
    {
        FitChange(() => {
            _chromosomesChild.Clear();// 选择的结果
                                      // 轮盘赌选择方法,用于选出前两个
            for (int i = 0; i < _chromosomes.Count; i++)
            {
                // int seed = i * 100 / 3;
                double rand = GeneticInfoBasal.Random.NextDouble();// 生成0.0-1.0之间的随机数,用于选择
                Console.WriteLine("挑选(杀死)的rand " + rand);
                if (rand < _chromosomes[0].Probability)
                    _chromosomesChild.Add(_chromosomes[0].Clone());
                else
                {
                    for (int j = 0; j < _chromosomes.Count - 1; j++)//-1是因为去除了第1个染色体
                    {
                        if (_chromosomes[j].Probability <= rand &&
                            rand <= _chromosomes[j + 1].Probability)            // 判断区间
                            _chromosomesChild.Add(_chromosomes[j + 1].Clone()); // j是从0开始的,
                    }
                }
            }
        });
    }

    /// <summary>
    /// 选择染色体方法:锦标赛
    /// </summary>
    public void SelectTournament()
    {
        // 1.产生两个不同的随机数作为要参加锦标赛的两个个体;
        // 2.判断适应度大小,
        // 小的被选择(最短路径)
        // 它和排序不一样的地方是,锦标赛并不一定拥有最短或最长(种群多样性)
        FitChange(() => {
            int count = 0;              // 选择的数量
            _chromosomesChild.Clear();  // 选择的结果
            while (count < _Info.ChromosomeNumber)
            {
                int test1 = GeneticInfoBasal.Random.Next(0, _Info.ChromosomeNumber);// 要参加锦标赛的的两个个体
                int test2 = GeneticInfoBasal.Random.Next(0, _Info.ChromosomeNumber);
                if (test1 != test2)
                {
                    Chromosome ch;
                    if (_chromosomes[test1].Fitness <= _chromosomes[test2].Fitness)// 适应度比较
                        ch = _chromosomes[test2];
                    else
                        ch = _chromosomes[test1];
                    _chromosomesChild.Add(ch.Clone());
                    count++;
                }
            }
        });
    }

    /// <summary>
    /// 挑选出最大适应值
    /// </summary>
    /// <returns></returns>
    public int GetMaxfit()
    {
        int maxfit = _chromosomes[0].Fitness;
        for (int i = 1; i < _chromosomes.Count; i++)
        {
            if (_chromosomes[i].Fitness > maxfit)
                maxfit = _chromosomes[i].Fitness;
        }
        return maxfit;
    }

    /// <summary>
    /// 重新计算fit值
    /// </summary>
    public void UpdateFitValue()
    {
        for (int i = 0; i < _chromosomes.Count; i++)
            _chromosomes[i].Fitness =
                GetFitValue(Helper.DeCode(_chromosomes[i].Bits));
    }



    /// <summary>
    /// 交叉(交配生子)
    /// </summary>
    public void Crossover()
    {
        /**         bit[5]~bit[0]   fit
         * 4        000 110         12
         * 3        001 010         9
         * child1   000 010         14
         * child2   001 110         5
         */
        // 选择交叉位置
        int bitNum = _chromosomes[0].Bits.Length;                // 获取染色体位数
        int rand1 = GeneticInfoBasal.Random.Next(0, bitNum);     // 生成0-染色体位数-1之间的随机数,
        int rand2 = GeneticInfoBasal.Random.Next(0, bitNum);
        if (rand1 > rand2)
        {
#pragma warning disable IDE0180 // 使用元组交换值
            var temp = rand1;
            rand1    = rand2;
            rand2    = temp;
#pragma warning restore IDE0180 // 使用元组交换值
        }
        Console.WriteLine("交叉(交配)的rand " + rand1 + " - " + rand2);

        // 第1条和第2条进行交配,两两一对
        for (int i = 0; i < _chromosomes.Count; i += 2)
        {
            int ii = i + 1;
            // 从随机数1 交叉 到随机数2结束
            for (int ra = rand1; ra <= rand2; ra++)
            {
                // 交换两段 基因段[随机数]
#pragma warning disable IDE0180 // 使用元组交换值
                int temp                  = _chromosomes[i].Bits[ra];
                _chromosomes[i].Bits[ra]  = _chromosomes[ii].Bits[ra];
                _chromosomes[ii].Bits[ra] = temp;
#pragma warning restore IDE0180 // 使用元组交换值
            }
            // 交配生成两条新染色体(二进制转码十进制)重新计算适应值
            _chromosomes[i].Fitness = GetFitValue(Helper.DeCode(_chromosomes[i].Bits));
            _chromosomes[ii].Fitness = GetFitValue(Helper.DeCode(_chromosomes[ii].Bits));
        }
    }

    /// <summary>
    /// 进化(变异)
    /// </summary>
    public void Mutate()
    {
        // 染色体数量
        int chromoNum = _chromosomes.Count;
        // 单个染色体基因数-1,去除用于判断正负的一个基因
        int geneNum = _chromosomes[0].Bits.Length - 1;
        // 在所有的基因数范围中选择一个随机数
        int varSite = GeneticInfoBasal.Random.Next(1, chromoNum * geneNum + 1);
        // 判断随机数<=基因总数*变异概率,判断是否发生突变// 每条染色体有5个决定基因(排除第一个决定正负的基因)
        if (varSite <= chromoNum * geneNum * _Info.MutateProbability)
        {
            Console.WriteLine("开始变异");

            int row = GeneticInfoBasal.Random.Next(0, chromoNum);// 确定要突变的染色体编号
            int col = GeneticInfoBasal.Random.Next(0, geneNum);  // 确定要突变的基因
            Console.WriteLine($"变异的位置 :第{row}条染色体的第{col}个基因");
            // 0变1,1变0
            if (_chromosomes[row].Bits[col] == 0)
                _chromosomes[row].Bits[col] = 1;
            else
                _chromosomes[row].Bits[col] = 0;
            _chromosomes[row].Fitness = GetFitValue(Helper.DeCode(_chromosomes[row].Bits));
        }
    }
    #endregion
}